#include <iostream>
#include <string>
#include <sys/ipc.h>
#include <string.h>
#include <sys/shm.h>
using std::cerr;
using std::endl;

class Shm
{
private:
    key_t _key = -1;
    int _shmid = -1;
    const void *_addr = nullptr;

private:
    int _CreatShm(key_t key, size_t size, int shmflg)
    {
        int shmid = shmget(key, size, shmflg);
        if (shmid < 0)
        {
            cerr << " shm creat error:" << strerror(errno) << endl;
            exit(1);
        }
        return shmid;
    }

public:
    key_t GetShmKey(const char *path, int proj_id)
    {
        key_t key = ftok(path, proj_id);
        if (key < 0)
        {
            cerr << "get key error:" << strerror(errno) << endl;
            exit(1);
        }
        return key;
    }
    int CreatShm(key_t key, size_t size)
    {
        int shmid = _CreatShm(key, size, IPC_CREAT | IPC_EXCL | 0666);

        return shmid;
    }
    int GetShm(key_t key, size_t size)
    {
        int shmid = _CreatShm(key, size, IPC_CREAT);
        return shmid;
    }

    void SetShm(key_t key, int shmid)
    {
        _key = key;
        _shmid = shmid;
    }

    void *ShmAttach(const void *shmaddr = nullptr)
    {
        void *addr = shmat(_shmid, shmaddr, 0);
        if (addr == (void *)-1)
        {
            cerr << "shm attach error:" << strerror(errno) << endl;
            exit(1);
        }
        _addr = addr;
        return addr;
    }

    void ShmDetach()
    {
        int n = shmdt(_addr);
        if (n < 0)
        {
            cerr << "shm detach error:" << strerror(errno) << endl;
            exit(1);
        }
    }
    void DeleteShm()
    {
        int n = shmctl(_shmid, IPC_RMID, nullptr);
        if (n < 0)
        {
            cerr << "shm deletes error:" << strerror(errno) << endl;
            exit(1);
        }
    }
    void ShmDebug()
    {
        struct shmid_ds buf;
        int n = shmctl(_shmid, IPC_STAT, &buf);
        if (n < 0)
        {
            cerr << "shm debug error:" << strerror(errno) << endl;
            exit(1);
        }
    }
};